//
//  UIView+HHEffects.swift
//  HHPatient
//
//  Created by chun.chen on 2021/8/31.
//  圆角 边框 阴影效果

import UIKit

public final class BCViewEffects<Base> {
    public let base: Base
    public init(_ base: Base) {
        self.base = base
    }

    // 阴影后置view
    public var shadowBackgroundView: UIView?
}

/*
 eg:
 view.bc.setup { (render) in
     render.shadowColor = .red
     render.shadowOpacity = 0.7
     render.shadowRadius = 5
     render.shadowOffset = CGSize(width: 0, height: 4)
     render.borderWidth = 10
     render.borderColor = .blue
     render.conrnerRadius = 12
     render.bounds = CGRect(x: 0, y: 0, width: 60, height: 60)
 }
 **/

public protocol BCViewEffectsCompatible {
    associatedtype CompatibleType
    var bc: CompatibleType { get }
}

public extension BCViewEffectsCompatible {
    var bc: BCViewEffects<Self> {
        return BCViewEffects(self)
    }
}

// MARK: - extensions

extension UIView: BCViewEffectsCompatible { }

public class BCViewRender {
    /// UIRectCorner 默认 UIRectCornerAllCorners
    public var conrnerCorner: UIRectCorner = .allCorners
    /// 圆角半径 默认 0.0
    public var conrnerRadius: CGFloat = 0
    /// 边框颜色 默认 nil
    public var borderColor: UIColor?
    /// 边框宽度 默认 0
    public var borderWidth: CGFloat = 0
    /// 阴影颜色 默认 nil
    public var shadowColor: UIColor?
    /// 阴影偏移方向和距离 默认 nil
    public var shadowOffset: CGSize?
    /// 阴影模糊度 默认 0
    public var shadowRadius: CGFloat = 0
    /// (0~1] 默认 0
    public var shadowOpacity: Float = 0
    /// 贝塞尔路径 默认 nil (有值时，radius属性将失效)
    public var bezierPath: UIBezierPath?
    /// 设置圆角时，会去获取视图的bounds属性，如果此时获取不到，则需要传入该参数，默认为 nil，如果传入该参数，则不会去回去视图的bounds属性了
    public var bounds: CGRect?
}

public extension BCViewEffects where Base: UIView {
    /// 设置圆角，边框，阴影
    /// - Parameter closure: read 渲染参数
    func setup(_ closure: (_ read: BCViewRender) -> Void) {
        let render = BCViewRender()
        closure(render)
        addShadow(render)
        addBorderRadius(render)
    }

    /// 清除设置
    func clear() {
        if let bgView = base.bc.shadowBackgroundView {
            bgView.removeFromSuperview()
            base.bc.shadowBackgroundView = nil
        }
        if let sublayers = base.layer.sublayers {
            for layer in sublayers {
                if layer.name == "CCViewEffects" {
                    layer.removeFromSuperlayer()
                }
            }
        }

        base.layer.masksToBounds = false
        base.layer.mask = nil
        base.layer.shadowPath = nil
    }

    /// 添加阴影
    /// - Parameter render: render description
    func addShadow(_ render: BCViewRender) {
        var shadowView = base as UIView
        // 同时存在阴影和圆角
        if (render.shadowOpacity > 0 && render.conrnerRadius > 0) || render.bezierPath != nil {
            if let bgView = base.bc.shadowBackgroundView {
                bgView.removeFromSuperview()
                base.bc.shadowBackgroundView = nil
            }
            // 添加一个阴影view
            assert(base.superview != nil, "添加阴影和圆角时，请先将view加到父视图上")
            shadowView = UIView(frame: base.frame)
            shadowView.translatesAutoresizingMaskIntoConstraints = false
            base.superview?.insertSubview(shadowView, belowSubview: base)

            let topConstraint = NSLayoutConstraint(item: shadowView, attribute: .top, relatedBy: .equal, toItem: base, attribute: .top, multiplier: 1, constant: 0)
            let leftConstraint = NSLayoutConstraint(item: shadowView, attribute: .left, relatedBy: .equal, toItem: base, attribute: .left, multiplier: 1, constant: 0)
            let rightConstraint = NSLayoutConstraint(item: shadowView, attribute: .right, relatedBy: .equal, toItem: base, attribute: .right, multiplier: 1, constant: 0)
            let bottomConstraint = NSLayoutConstraint(item: shadowView, attribute: .bottom, relatedBy: .equal, toItem: base, attribute: .bottom, multiplier: 1, constant: 0)
            base.superview?.addConstraints([topConstraint, leftConstraint, rightConstraint, bottomConstraint])
            base.bc.shadowBackgroundView = shadowView
        }
        // 圆角
        if render.conrnerRadius > 0 || render.bezierPath != nil {
            shadowView.layer.shadowPath = drawBezierPath(render).cgPath
        }

        // 阴影
        shadowView.layer.masksToBounds = false
        shadowView.layer.shadowOpacity = render.shadowOpacity
        shadowView.layer.shadowRadius = render.shadowRadius
        if let shadowOffset = render.shadowOffset {
            shadowView.layer.shadowOffset = shadowOffset
        }
        if let shadowColor = render.shadowColor {
            shadowView.layer.shadowColor = shadowColor.cgColor
        }
    }

    /// 添加边框圆角
    /// - Parameter render: render description
    func addBorderRadius(_ render: BCViewRender) {
        // 圆角或阴影或自定义曲线
        if render.conrnerRadius > 0 || render.shadowOpacity > 0 || render.bezierPath != nil {
            // 圆角
            if render.conrnerRadius > 0 || render.bezierPath != nil {
                let maskLayer = CAShapeLayer()
                maskLayer.frame = base.bounds
                maskLayer.path = drawBezierPath(render).cgPath
                base.layer.mask = maskLayer
            }
            // 边框
            if render.borderWidth > 0 || render.bezierPath != nil {
                // 移除之前的
                if let sublayers = base.layer.sublayers {
                    for layer in sublayers {
                        if layer.name == "CCViewEffects" {
                            layer.removeFromSuperlayer()
                        }
                    }
                }
                //
                let layer = CAShapeLayer()
                layer.name = "CCViewEffects"
                layer.frame = base.bounds
                layer.path = drawBezierPath(render).cgPath
                layer.lineWidth = render.borderWidth
                layer.strokeColor = render.borderColor?.cgColor
                layer.fillColor = UIColor.clear.cgColor
                base.layer.addSublayer(layer)
            }

        } else {
            // 只有边框
            base.layer.masksToBounds = true
            base.layer.borderWidth = render.borderWidth
            base.layer.borderColor = render.borderColor?.cgColor
        }
    }

    // MARK: - help

    func drawBezierPath(_ render: BCViewRender) -> UIBezierPath {
        guard let bezierPath = render.bezierPath else {
            return UIBezierPath(roundedRect: drawBounds(render), byRoundingCorners: render.conrnerCorner, cornerRadii: CGSize(width: render.conrnerRadius, height: render.conrnerRadius))
        }
        return bezierPath
    }

    func drawBounds(_ render: BCViewRender) -> CGRect {
        // 1.如果传入了大小，则直接返回
        if let bounds = render.bounds {
            return bounds
        }
        // 2.没有父视图 返回zero
        guard let superview = base.superview else {
            return CGRect.zero
        }
        // 3.获取在自动布局时的视图大小
        if superview.bounds.width == 0 || superview.bounds.height == 0 {
            superview.layoutIfNeeded()
        }
        return superview.bounds
    }
}
